import Rules from "./rules"
/**
 * [validator description]
 * @authors zhanwang.ye
 * @return {[type]}                                                                [description]
 */
function Validator(Vue){
	var _ = Vue.util;
    var FragmentFactory = Vue.FragmentFactory;
    var vIf = Vue.directive('if');
    var camelize = _.camelize;

    Vue.elementDirective('validator', {
      	params: ['name', 'groups'],
      	bind:function(){
      		var self=this,
      		params=self.params;
      		self._validatorName=params.name;
      		self.setupValidator();
      		self.setupFragment(params.lazy);
      	},
      	update:function(value,old){

      	},
      	setupValidator:function(){
      		var self=this,
      		_vm=self.vm;
      		self.validatorName="$"+self._validatorName;
      		_.defineReactive(_vm,self.validatorName);
      	},
      	setupFragment:function(lazy) {
	        var self = this,
	        _vm = self.vm;
			self.anchor = _.createAnchor('vue-validator');
			_.replace(self.el, self.anchor);
			_.extend(_vm.$options, { _validator: self.validatorName });
			self.factory = new FragmentFactory(_vm, self.el.innerHTML);
			vIf.insert.call(self);
	    }
  	});

  	/**
  	 * [validate directive]
  	 * @authors zhanwang.ye
  	 * @return {[type]}                                       [description]
  	 */
	Vue.directive("validate",{
		acceptStatement:true,
		params:[
			"validate-handler",
			"validate-messages",
			"validate-callback"
		],
		paramWatchers:{
			"validateHandler":function(val){
				this.params.validateHandler=val;
			},
			"validateMessages":function(val){
				this.params.validateMessages=val;
			},
			"validateCallback":function(val){
				this.params.validateCallback=val;
			}
		},
		bind:function(){
			var self=this,
			$el=self.el;
			self.setValidator();
			self.handler();

		},
		update:function(value,old){

		},
		setValidator:function(){
			var self=this,
				_vm=self.vm,
				_=Vue.util,
				_expression=self.expression,
				_validateRules,
				_validMessages={},
				_errorMsg;
			
			
			if(_expression!=null||_expression!=""){
				_validateRules=$evalExpression(_expression,_vm);
				if(self.params.validateMessages){
					_validMessages=$evalExpression(self.params.validateMessages,_vm);
					
				}
				for(var key in _validateRules){
					_errorMsg=_validMessages[key];
					break;
				}
				//console.log(_errorMsg);
				var validator=_vm.$options._validator;
				self._model=self.arg;
				_vm.$set(validator+"."+self._model,{
					"field":self._model,
					"invalid":false,
					"error":true,
					"errorMsg":_errorMsg,
					"messages":_validMessages,
					"rules":_validateRules
				});
			}
		},
		handler:function(){
			var self=this,
			validEvent=self.params.validateHandler,
			_callback=self.params.validateCallback;
			if(validEvent=="false") return;
			$detectEvent(self,validEvent,_callback);
		}
	});
}


function $getValidator(self){
	var _vm=self.vm,
	validator=_vm.$options._validator;
	return _vm[validator][self._model];
}

function $detectEvent(self,eventName,callback){
	var $el=self.el,
	_vm=self.vm,
	_event="on"+eventName,
	validator=_vm[_vm.$options._validator];

	$el.onchange=function(ev){
		var value=getFieldValue($el);
		validate(value,self);
	};

	$el.onblur=function(ev){
		var value=getFieldValue($el);
		validate(value,self);
	};

	$el.oninput=function(ev){
		var value=getFieldValue($el);
		validate(value,self);
	}
}

/**
 * [getFieldType description]
 * @authors zhanwang.ye
 * @param  {[type]} el [description]
 * @return {[type]}    [description]
 */
function getFieldValue(el){
	var inputType=el.getAttribute("type");
	var nodeName=el.nodeName;

	if(nodeName=="INPUT"){
		if(inputType==""||inputType=="text"){
			return el.value;
		}
		if(inputType=="checkbox"){
			if(el.checked==true){
				return el.value;
			}else{
				return "";
			}
		}
		if(inputType=="radio"){
			return el.value;
		}
	}

	if(nodeName=="SELECT"){
		return el.value;
	}

	if(nodeName=="TEXTAREA"){
		return el.text;
	}
	
	return "";
}
/**
 * javascript String to Object
 * @authors zhanwang.ye
 * @param  {[type]} expression [description]
 * @param  {[type]} $vm        [description]
 * @return {[type]}            [description]
 */
function $evalExpression(expression,_vm){
	var _exObj;
	try{
		_exObj=_vm.$eval(expression);
	}catch(err){
		throw new Error(err);
	}

	return _exObj;
}

/**
 * [validate description]
 * @authors zhanwang.ye
 * @param  {[type]} value [description]
 * @return {[type]}       [description]
 */
function validate(value,self){
	var _vm=self.vm;
	var validator=$getValidator(self);
	var rules=validator.rules;
	var returnMsg="";
	if(typeof rules !="object"){
		return;
	}
	else{
		var _valid=valid(value,rules);
		validError(self,_valid);
	}
}



/**
 * [valid description]
 * @authors zhanwang.ye
 * @param  {[type]} value    [description]
 * @param  {[type]} rules    [description]
 * @param  {[type]} messages [description]
 * @return {[type]}          [description]
 */
function valid(value,rules){
	var isValid=true;
	for(var key in rules){
		var _validFunc=Rules[key];
		if(typeof _validFunc=="function"){
			isValid=_validFunc(value);
		}
		if(!isValid){
			return {
				isValid:isValid,
				ruleName:key
			}
		} 
	}
	return {
		isValid:isValid,
		ruleName:key
	};
}


/**
 * [validError description]
 * @authors zhanwang.ye
 * @param  {[type]} ruleName  [description]
 * @param  {[type]} validator [description]
 * @return {[type]}           [description]
 */
function validError(self,validObj){
	var _vm=self.vm,
	$el=self.el;
	var validator=$getValidator(self);
	var fieldName=self._model;
	validator.error=validObj.isValid?false:true;
	validator.invalid=true;
	validator.errorMsg=validator.messages[validObj.ruleName];
	// console.log(validator.error);
	_vm[_vm.$options._validator][fieldName]=validator;
}

/**
 * init validator
 * @authors zhanwang.ye
 * @param  {[type]} typeof window        ! [description]
 * @return {[type]}        [description]
 */
// if (typeof window !== 'undefined' && window.Vue) {
// 	window.Vue.use(Validator);
// }

module.exports=Validator;


